/**
 * @author : andy
 * @description : 路由守卫
 */
import type { Router, RouteRecordRaw } from "vue-router";
import { startProgress, stopProgress } from "./nprogress";
import { generateAccessRoutes, traverseTreeValues } from "./utils";
import { dynamicRoutes, routeWhitelist } from "./routes";
import { useAccessStore } from "@/stores/access/access";
import { useUserStore } from "@/stores/access/user";
import { useAuthStore } from "@/stores/access/auth";
import { useConfigStore } from "@/stores/configs/config";
import Auth from "@/services/auth";
import { getMenuList } from "@/apis/mock/user";
import type { AccessMenuItem } from "@/stores/access/types";
type LoginReturnType = {
  url?: string;
} | boolean | undefined;

let hasAddRoutes = false;

const getAppConfig = () => {
  return localStorage.getItem('app_config') ? JSON.parse(localStorage.getItem('app_config')!) : undefined; 
}

const setKeepAlivePages = (menus: AccessMenuItem[] , keepAliveRoutes: RouteRecordRaw[] , routes: RouteRecordRaw[]) => {
  const accessStore = useAccessStore();
  let paths = traverseTreeValues(menus , node => node.path , {childProps : 'children'});
  const paths2 = traverseTreeValues(keepAliveRoutes , node => node.path , { childProps : 'children' });
  paths = [...new Set([...paths , ...paths2])];
  const traverse = (routes: RouteRecordRaw[]) => {
    routes.forEach(async route => {
      if (paths.includes(route.path)) {
        if (route.component) {
          const page: Record<string , unknown> = await (route.component as () => Record<string , unknown>)();
          const name = (page.default as {name: string}).name;
          if (name && !accessStore.hasKeepAlivePage(name)) {
            accessStore.addKeepAlivePages(name)
          }
        }
      }
      if (route.children && route.children.length > 0) {
        traverse(route.children);
      }
    })
  }
  traverse(routes);
  traverse(keepAliveRoutes);
}

/**
 * 设置通用路由导航
 * @param router router对象
 */
function setupCommonGuard (router: Router) {
  const loadedPaths = new Set<string>();
  router.beforeEach(to => {
    to.meta.loaded = loadedPaths.has(to.path);
    const appConfig = getAppConfig();
    if (!to.meta.loaded && appConfig?.config?.transition?.progress) {
      startProgress();
    }
    return true;
  });
  router.afterEach(to => {
    const appConfig = getAppConfig();
    if (appConfig?.config?.tabbar?.enable) {
      loadedPaths.add(to.path);
    }
    if (appConfig?.config?.transition?.progress) {
      stopProgress();
    }
    if (appConfig?.config?.app?.dynamicTitle) {
      const title = appConfig?.config?.app?.name;
      document.title = to.meta.title as string || title;
    }
  });
}

/**
 * 设置权限路由导航
 * @param router router对象
 */
function setupAccessGuard (router: Router) {
  router.beforeEach(async to => {
    const accessStore = useAccessStore();
    const userStore = useUserStore();
    const authStore = useAuthStore();
    const configStore = useConfigStore();
    // 初始化Auth功能，用于登录
    Auth.initAuth();
    // 路由白名单，不需要进行权限拦截，可以直接访问
    if (routeWhitelist.includes(to.name)) {
      return true;
    }
    // 对接用户登录的逻辑
    // 检查用户是否已经登录，如果没有登录，则登录
    if (!Auth.checkLogin()) {
      try {
        // 返回可能是一个布尔值或者一个{url: 重定向地址}，如果异常会返回false，如果正常会返回{url:重定向地址}
        // 如果登录异常，那么就跳转到登录页面，重新登录
        const result: LoginReturnType = await Auth.login({url : to.fullPath});
        if (result) {
          return (result as {url: string}).url;
        } else {
          return false;
        }
      } catch (err) {
        console.log(err);
        await Auth.login({url : to.fullPath});
      }
    }
    // 是否已经检查过权限，如果已经检查过权限，那么表示不需要再获取菜单，用户信息
    if (accessStore.isAccessChecked) {
      return true
    }
    const { data : menus } = await getMenuList();
    // 调用接口获取用户信息
    if (!userStore.userInfo) {
      await authStore.getUser();
    }
    // 根据菜单生成权限路由列表
    const { accessRoutes , iframeMenus , keepAliveMenus , keepAliveRoutes } = generateAccessRoutes([...dynamicRoutes] , menus);
    // 根据缓存的菜单列表配置需要缓存的路由
    if (configStore.config.tabbar.keepAlive) {
      setKeepAlivePages(keepAliveMenus as AccessMenuItem[] , keepAliveRoutes as RouteRecordRaw[] , accessRoutes);
    } else {
      accessStore.clearKeepAlivePages();
    }
    // 添加动态路由 
    if (!hasAddRoutes) {
      accessRoutes.forEach(route => {
        router.addRoute(route);
      })
      hasAddRoutes = true;
      // 保存菜单和路由
      accessStore.setAccessMenus(menus);
      accessStore.setAccessRoutes(accessRoutes);
      accessStore.setIsAccessChecked(true);
      accessStore.setIframeMenus(iframeMenus as AccessMenuItem[]);
      return to.fullPath;
    }
  })
}


function setupRouteGuard (router: Router) {
  setupCommonGuard(router);
  setupAccessGuard(router);
}

export {
  setupRouteGuard
}